package why.demo.list.config;

import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

/**
 * CORS响应配置
 * 
 * 专门解决"请求能发出，但响应被浏览器拦截"的问题
 * 确保所有响应都包含正确的CORS头部
 * 
 * @author why
 * @date 2025/9/24
 */
@Slf4j
//@Configuration
public class CorsResponseConfig {

    @Bean
    public GlobalFilter corsResponseFilter() {
        return new CorsResponseFilter();
    }
    
    /**
     * CORS响应过滤器
     */
    private static class CorsResponseFilter implements GlobalFilter, Ordered {
        
        private static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(CorsResponseFilter.class);
        
        @Override
        public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
            ServerHttpRequest request = exchange.getRequest();
            ServerHttpResponse response = exchange.getResponse();
            
            String origin = request.getHeaders().getOrigin();
            String method = request.getMethod() != null ? request.getMethod().name() : "UNKNOWN";
            String path = request.getURI().getPath();
            
            logger.info("CORS处理: {} {} Origin: {}", method, path, origin);
            
            // 处理OPTIONS预检请求
            if (HttpMethod.OPTIONS.equals(request.getMethod())) {
                return handlePreflightRequest(exchange, origin);
            }
            
            // 为实际请求添加CORS头部
            addCorsHeaders(response, origin);
            
            return chain.filter(exchange)
                    .doOnSuccess(aVoid -> {
                        // 确保响应完成后CORS头部仍然存在
                        logger.debug("响应完成，CORS头部: Origin={}", 
                                response.getHeaders().getFirst(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN));
                    })
                    .doOnError(throwable -> {
                        // 即使出错也要确保CORS头部存在
                        addCorsHeaders(response, origin);
                        logger.error("请求处理出错，已添加CORS头部: {}", throwable.getMessage());
                    });
        }
        
        /**
         * 处理OPTIONS预检请求
         */
        private Mono<Void> handlePreflightRequest(ServerWebExchange exchange, String origin) {
            ServerHttpResponse response = exchange.getResponse();
            
            logger.info("处理OPTIONS预检请求，Origin: {}", origin);
            
            // 添加预检请求需要的所有CORS头部
            addCorsHeaders(response, origin);
            
            // 预检请求特有的头部
            response.getHeaders().add(HttpHeaders.ACCESS_CONTROL_ALLOW_METHODS, 
                    "GET,POST,PUT,DELETE,OPTIONS,HEAD,PATCH");
            response.getHeaders().add(HttpHeaders.ACCESS_CONTROL_ALLOW_HEADERS, 
                    "Origin,Content-Type,Accept,Authorization,Cookie,X-Requested-With," +
                    "Access-Control-Request-Method,Access-Control-Request-Headers," +
                    "X-Token,X-User-Id,Cache-Control,X-Request-Id");
            response.getHeaders().add(HttpHeaders.ACCESS_CONTROL_MAX_AGE, "3600");
            
            response.setStatusCode(HttpStatus.OK);
            return response.setComplete();
        }
        
        /**
         * 添加CORS响应头
         */
        private void addCorsHeaders(ServerHttpResponse response, String origin) {
            HttpHeaders headers = response.getHeaders();
            
            // 设置允许的源
            String allowOrigin = determineAllowOrigin(origin);
            headers.set(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN, allowOrigin);
            
            // 允许携带凭证
            headers.set(HttpHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS, "true");
            
            // 暴露给前端的响应头
            headers.set(HttpHeaders.ACCESS_CONTROL_EXPOSE_HEADERS, 
                    "Content-Type,Content-Length,Authorization,X-Total-Count,X-Request-Id," +
                    "Cache-Control,Content-Disposition,X-Token");
            
            logger.debug("添加CORS头部: Origin={}, Credentials=true", allowOrigin);
        }
        
        /**
         * 确定允许的源
         */
        private String determineAllowOrigin(String origin) {
            // 如果请求包含Origin头，使用该Origin
            if (origin != null && !origin.isEmpty()) {
                // 可以在这里添加Origin白名单验证
                if (isAllowedOrigin(origin)) {
                    return origin;
                }
            }
            
            // 默认允许localhost:8080（前端开发服务器）
            return "http://localhost:8080";
        }
        
        /**
         * 检查Origin是否在允许列表中
         */
        private boolean isAllowedOrigin(String origin) {
            // 允许的Origin列表
            return origin.equals("http://localhost:8080") ||
                   origin.equals("http://localhost:3000") ||
                   origin.equals("http://127.0.0.1:8080") ||
                   origin.equals("http://127.0.0.1:3000");
        }
        
        @Override
        public int getOrder() {
            // 设置高优先级，但不是最高，确保在路由之前但在其他业务过滤器之后
            return Ordered.HIGHEST_PRECEDENCE + 1;
        }
    }
}
